<?php

/* ========================================================================= */
/* This file is part of the HypnoPHP Framework Library                       */
/* Copyright (c) 2009-2010, Radu Buzea                                       */
/* ========================================================================= */

/**
 @author Radu Buzea
 @copyright Copyright (c) 2009-2010, Radu Buzea (www.hypnosis.ro)
 @license GNU Lesser General Public License (www.gnu.org/copyleft/lesser.html)
 @package MySQL Module for HypnoPHP
*/

global $__mysql_field_float_types, $__mysql_field_int_types, $__mysql_field_str_types;

$__mysql_field_float_types = array(
	'DECIMAL' => true,
	'DOUBLE' => true,
	'FLOAT' => true,
	'NUMERIC' => true,
	'REAL' => true,
);

$__mysql_field_int_types = array(
	'BIGINT' => true,
	'INT' => true,
	'INTEGER' => true,
	'MEDIUMINT' => true,
	'SMALLINT' => true,
	'TINYINT' => true,
);

$__mysql_field_str_types = array(
	'BLOB' => true,
	'CHAR' => true,
	'ENUM' => true,
	'LONGBLOB' => true,
	'LONGTEXT' => true,
	'MEDIUMBLOB' => true,
	'MEDIUMTEXT' => true,
	'SET' => true,
	'TEXT' => true,
	'TINYBLOB' => true,
	'TINYTEXT' => true,
	'VARCHAR' => true,
);

// ============================================================================
// Class: Module_MySQL_Field
// ============================================================================

class Module_MySQL_Field extends HBaseDbField
{

	/*
		Function: __initialize
		----------------------------------------
	*/
	public function __initialize()
	{
		if (func_num_args() > 0) {
			$obj = func_get_arg(0);
			if (is_object($obj) && get_class($obj) == 'stdClass') {
				if (isset($obj->name)) { $this->name = $obj->name; }
				if (isset($obj->table)) { $this->table_name = $obj->table; }
				if (isset($obj->type)) { $this->type = strtoupper($obj->type); }
				if (isset($obj->def)) { $this->default = $obj->def; }
				if (isset($obj->max_length)) { $this->max_length = $obj->max_length; }
				if (isset($obj->not_null)) { $this->null = ($obj->not_null == 0); }
				if (isset($obj->primary_key)) { $this->primary_key = ($obj->primary_key == 1); }
				if (isset($obj->multiple_key)) { $this->multiple_key = ($obj->multiple_key == 1); }
				if (isset($obj->unique_key)) { $this->unique_key = ($obj->unique_key == 1); }
				if (isset($obj->numeric)) { $this->is_numeric = ($obj->numeric == 1); }
				if (isset($obj->blob)) { $this->is_blob = ($obj->blob == 1); }
				if ($this->is_numeric) {
					if (isset($obj->unsigned)) { $this->unsigned = ($obj->unsigned == 1); }
					if (isset($obj->zerofill)) { $this->zerofill = ($obj->zerofill == 1); }
				}
				unset($obj);
			}
		}
	}

	/*
		Function: validate_data
		----------------------------------------
	*/
	public function validateData($data = null, &$error = null)
	{
		if (is_null($data)) { return $this->default; }
		$error = "";
		$type = strtoupper($this->__type);
		switch ($type) {
			case 'DECIMAL':
			case 'DOUBLE':
			case 'FLOAT':
			case 'NUMERIC':
			case 'REAL':
				$length = $this->__length;
				if (!is_array($length) || count($length) < 2) {
					$error = "INVALID $type LENGTH";
					return $this->default;
				}
				$max_int = intval($length[0]);
				if ($max_int > 65) { $max_int = 65; }
				$max_dec = intval($length[1]);
				if ($type != 'DECIMAL' && $type != 'NUMERIC') {
					$max_int = $max_int - $max_dec;
				}
				$max_val = '';
				for ($i = 0; $i < $max_int; $i++) { $max_val .= '9'; }
				$max_val .= '.';
				for ($i = 0; $i < $max_dec; $i++) { $max_val .= '9'; }
				$max_val = floatval($max_val);
				$unsigned = (!is_null($this->unsigned) && $this->unsigned);
				$min_val = $unsigned ? 0 : -$max_val;
				if (!is_float($data)) { $data = floatval($data); }
				if ($data > $max_val) {
					$data = $max_val;
					$error = "$type VALUE IS GREATER THAN THE MAX. LIMIT OF $max_val";
				} elseif ($data < $min_val) {
					$data = $min_val;
					$error = "$type VALUE IS LESS THAN THE MIN. LIMIT OF $min_val";
				}
				return $data;
				break;
			case 'BIGINT':
			case 'INT':
			case 'INTEGER':
			case 'MEDIUMINT':
			case 'SMALLINT':
			case 'TINYINT':
				$length = intval($this->__length);
				if (!is_int($data)) { $data = intval($data); }
				if (strlen($data) > $length) {
					$data = '';
					for ($i = 0; $i < $length; $i++) { $data .= '9'; }
					$data = intval($data);
				} else {
					$unsigned = (!is_null($this->unsigned) && $this->unsigned);
					switch ($type) {
						case 'BIGINT':
							if ($unsigned) {
								if ($data >= 0) { return $data; }
								else { return 0; }
							}
							return $data;
							break;
						case 'INT':
						case 'INTEGER':
							if ($unsigned) {
								$min_val = 0;
								$max_val = 4294967295;
							} else {
								$min_val = -2147483648;
								$max_val = 2147483647;
							}
							break;
						case 'MEDIUMINT':
							if ($unsigned) {
								$min_val = 0;
								$max_val = 16777215;
							} else {
								$min_val = -8388608;
								$max_val = 8388607;
							}
							break;
						case 'SMALLINT':
							if ($unsigned) {
								$min_val = 0;
								$max_val = 65535;
							} else {
								$min_val = -32768;
								$max_val = 32767;
							}
							break;
						case 'TINYINT':
							if ($unsigned) {
								$min_val = 0;
								$max_val = 255;
							} else {
								$min_val = -128;
								$max_val = 127;
							}
							break;
					}
					if ($data > $max_val) {
						$data = $max_val;
						$error = "$type VALUE IS GREATER  THAN THE MAX. LIMIT OF $max_val";
					} elseif ($data < $min_val) {
						$data = $min_val;
						$error = "$type VALUE IS LESS THAN THE MIN. LIMIT OF $min_val";
					}
					return $data;
				}
				break;
			case 'CHAR':
			case 'VARCHAR':
			case 'STRING':
				$length = intval($this->__length);
				if (HValidation::string_validator($data, $length, ($type == 'CHAR'))) { return $data; }
				$error = "INVALID $type VALUE";
				break;
			case 'DATE':
			case 'DATETIME':
			case 'TIME':
			case 'TIMESTAMP':
			case 'YEAR':
				if (HValidation::datetime_validator($data, strtolower($type))) { return $data; }
				$error = "INVALID $type VALUE";
				break;
			case 'ENUM':
				$values = $this->__length;
				if (is_array($values) && in_array($data, $values)) { return $data; }
				$error = "INVALID $type VALUE";
				break;
			case 'SET':
				$values = $this->__length;
				if (!is_array($data)) {
					if (is_string($data)) {
						if (strstr($data, ',')) { $data = explode(',', $data); }
						else if (strstr($data, ';')) { $data = explode(';', $data); }
						else { $data = array($data); }
					} else {
						$data = array(strval($data));
					}
				}
				if (is_array($values)) {
					$raw_data = $data;
					$data = '';
					foreach ($raw_data as $value) {
						if (in_array($value, $values)) {
							if ($data != '') { $data = ','; }
							$data .= $value;
						}
					}
					return $data;
				}
				$error = "INVALID $type VALUE";
				break;
			case 'TINYBLOB':
			case 'TINYTEXT':
				$length = 256;
				if (HValidation::string_validator($data, $length, false)) { return $data; }
				$error = "INVALID $type VALUE";
				break;
			case 'BLOB':
			case 'TEXT':
				$length = 65536;
				if (HValidation::string_validator($data, $length, false)) { return $data; }
				$error = "INVALID $type VALUE";
				break;
			case 'LONGBLOB':
			case 'LONGTEXT':
				$length = 4294967296;
				if (HValidation::string_validator($data, $length, false)) { return $data; }
				$error = "INVALID $type VALUE";
				break;
			case 'MEDIUMBLOB':
			case 'MEDIUMTEXT':
				$length = 16777216;
				if (HValidation::string_validator($data, $length, false)) { return $data; }
				$error = "INVALID $type VALUE";
				break;
		}
		return $this->default;
	}

	/*
		Function: generate_cahce_code
		----------------------------------------
	*/
	public function generateCahceCode()
	{
		$result = "\$col = new " . __CLASS__ . "();\n\t\$col->name = \"" .
			addslashes($this->name) . "\";\n";
		if ($this->table != '') {
			$result .= "\t\$col->table = \"" . addslashes($this->table) . "\";\n";
		}
		if ($this->schema != '') {
			$result .= "\t\$col->schema = \"" . addslashes($this->schema) . "\";\n";
		}
		if ($this->length > 0) {
			$result .= "\t\$col->length = " . $this->length . ";\n";
		}
		if ($this->index > -1) {
			$result .= "\t\$col->index = " . $this->index . ";\n";
		}
		if (is_string($this->type)) {
			$result .= "\t\$col->type = '" . $this->type . "';\n";
		}
		if (is_array($this->properties))
		foreach ($this->properties as $key => $value) {
			$result .= "\t\$col->$key = ";
			switch (gettype($value)) {
				case 'boolean': $result .= ($value) ? 'true;' : 'false;'; break;
				case 'integer': $result .= $value . ";"; break;
				case 'double': $result .= $value . ";"; break;
				case 'string': $result .= "'" . addslashes($value) . "';"; break;
				default: $result .= "null; // Invalid data type '" . gettype($value) . "'";
			}
			$result .= "\n";
		}
		return $result;
	}

	/*
		Function: cast_value
		----------------------------------------
	*/
	public function cast_value($value)
	{
		$type = strtoupper($this->__type);
		switch ($type) {
			case 'DECIMAL':
			case 'DOUBLE':
			case 'FLOAT':
			case 'NUMERIC':
			case 'REAL':
				if (is_null($value) || !is_numeric($value)) { return 0; }
				return floatval($value);
			case 'BIGINT':
			case 'INT':
			case 'INTEGER':
			case 'MEDIUMINT':
			case 'SMALLINT':
			case 'TINYINT':
				if (is_null($value) || !is_numeric($value)) { return 0; }
				return intval($value);
			case 'DATE':
				if (is_null($value) || !is_string($value)) { return 0; }
				if (strlen($value) == 10) {
					$result = strtotime($value. ' 00:00:00');
					if ($result !== false) { return $result; }
				}
				return 0;
			case 'DATETIME':
			case 'TIMESTAMP':
				if (is_null($value) || !is_string($value)) { return 0; }
				if (strlen($value) == 19) {
					$result = strtotime($value. ' 00:00:00');
					if ($result !== false) { return $result; }
				}
				return 0;
			case 'TIME':
				if (is_null($value) || !is_string($value)) { return 0; }
				if (strlen($value) == 8) {
					$result = strtotime(date('Y-m-d') . ' ' . $value);
					if ($result !== false) { return $result; }
				}
				return 0;
			case 'YEAR':
				if (is_null($value) || !is_numeric($value)) { return 0; }
				return intval($value);
			default:
				return strval($value);
		}
	}

}
